<template>
  <uni-card class="my-exer-page" :is-full="true" spacing="0">
    <swiper
      :current="swiperIndex"
      :circular="true"
      @change="(e: any) => synIndex(e.detail.current, e.detail.source)"
    >
      <swiper-item v-for="(question, index) in questions" :key="index">
        <xm-question
          :no="`${curQuestionIndex + 1} / ${questionNum}`"
          v-model="question.userAnswers"
          :type="question.type"
          :markType="question.markType"
          :title="question.title"
          :score="question.score"
          :answers="question.answers"
          :userScore="question.userScore"
          :options="question.options"
          :editable="exer.answerShow"
          :errMark="exer.answerShow && question.userScore != null"
          :answersShow="!exer.answerShow"
          @change="autoNext(question)"
        ></xm-question>
      </swiper-item>
    </swiper>
    <template #title>
      <view class="my-exer-page-head">
        <view
          class="button"
          :class="{ active: exer.answerShow }"
          @click="changeAnswer(true)"
        >
          <span :class="size"> 答题模式</span>
        </view>
        <view
          class="button"
          :class="{ active: !exer.answerShow }"
          @click="changeAnswer(false)"
        >
          <span :class="size"> 背题模式 </span>
        </view>

        <!-- <uni-fav :checked="isFav" class="favBtn" @click="favClick" /> -->
      </view>
    </template>
    <template #actions>
      <FeedbackComponent
        v-if="curQuestionId"
        feedbackTitle="题目纠错"
        :questionId="curQuestionId"
        class="my-exer-page-feedback"
      />
      <view @click="answerSheet.open()" :class="size">
        <uni-icons custom-prefix="iconfont" type="icon-datika"></uni-icons>
        <text>答题卡</text>
      </view>
      <view @click="next" :class="size">
        <uni-icons custom-prefix="iconfont" type="icon-arrow-right"></uni-icons>
        <text>下一题</text>
      </view>
      <view v-if="isFav" @click="favClick(false)" :class="size">
        <uni-icons type="heart-filled"></uni-icons>
        <text>已收藏</text>
      </view>
      <view v-else @click="favClick(true)" :class="size">
        <uni-icons type="heart"></uni-icons>
        <text>收藏</text>
      </view>
      <view :class="size">
        <FontSet @fontSet="fontSet" :size="size" />
      </view>
      <view @click="exerEnd()" :class="size">
        <uni-icons custom-prefix="iconfont" type="icon-duigoux"></uni-icons>
        <text>完成</text>
      </view>
    </template>
    <uni-popup ref="answerSheet" type="share" safeArea backgroundColor="#fff">
      <uni-card
        title="答题卡"
        :isFull="true"
        sub-title=""
        extra=""
        spacing="0"
        class="my-exer-page-card"
      >
        <uni-grid
          :column="10"
          :highlight="true"
          @change=""
          class="my-exer-page-card-tips"
        >
          <uni-grid-item class="my-exer-page-card-do"></uni-grid-item>
          <text>已答</text>
          <uni-grid-item class="my-exer-page-card-true"></uni-grid-item>
          <text>答对</text>
          <uni-grid-item class="my-exer-page-card-false"></uni-grid-item>
          <text>答错</text>
        </uni-grid>
        <scroll-view scroll-y="true" style="height: 40vh">
          <uni-grid
            :column="10"
            :highlight="true"
            @change=""
            class="my-exer-page-card-tips"
          >
            <template
              v-for="(questionId, index) in getQuestionIds()"
              :key="questionId"
            >
              <uni-grid-item
                @click="curQuestionIndex = index"
                :class="{
                  'my-exer-page-card-do': hasDo(questionId),
                  'my-exer-page-card-mark': hasMark(questionId),
                  'my-exer-page-card-true': hasTrue(questionId),
                  'my-exer-page-card-false': hasFalse(questionId),
                }"
                >{{ index + 1 }}
              </uni-grid-item>
            </template>
          </uni-grid>
        </scroll-view>
      </uni-card>
    </uni-popup>
  </uni-card>
</template>

<script lang="ts" setup>
import { ref, reactive, computed, watch, watchEffect } from "vue";
import XmQuestion from "@/components/xm-question/xm-questionExer.vue";
import FeedbackComponent from "@/components/feedback/feedback.vue";
import FontSet from "@/components/fontSet/fontSet.vue";
import { onLoad } from "@dcloudio/uni-app";
import { Question } from "@/ts";
import http from "@/utils/request";
import { noticStore } from "@/stores/notic";

// 定义变量
const noticFn = noticStore();
const answerSheet = ref();
const exer = reactive({
  // 练习信息
  questionTypeId: 0, // 练习ID
  questionIds: [] as number[], // 试题列表
  answerShow: true, // 答题模式
  orderShow: [true], // 顺序显示
  rmkShow: [false], // 评论显示
  firstTime: new Date(), // 第一次进入时间
  lastTime: new Date(), // 最后一次答题时间
});
const swiperIndex = ref(0); // 滑块索引
const curQuestionIndex = ref(-1); // 当前试题索引
const questions = ref([] as Question[]); //试题数组
const questionCache = reactive({} as { [questionId: number]: Question }); // 试题缓存
const markQuestions = ref([] as number[]);

// 页面加载完毕，执行如下方法
onLoad(async (option) => {
  uni.setNavigationBarTitle({
    title: option.pageTitle, // 使用数据绑定的标题变量
  });
  // 获取我的练习
  exer.questionTypeId = parseInt(option.questionTypeId as string);
  let { data } = await http.post("myExer/questionBaseList", {
    questionTypeId: exer.questionTypeId,
  });
  exer.questionIds.push(...data);

  if (exer.questionIds.length) {
    // 触发curQuestionIndex监听
    let flag = false;
    noticFn.baseExerInfo.forEach((item) => {
      if (item.id == exer.questionTypeId) {
        flag = true;
      }
    });
    if (!flag) {
      let { data, code } = await http.post("exmMyExer/get", { type: 2 });
      if (code == 200) {
        try {
          noticFn.baseExerInfo = JSON.parse(data);
        } catch (error) {
          console.error("解析 JSON 数据出错：", error);
          // 在解析失败时进行处理，例如给出错误提示、记录日志等
        }
      }
    }
    //读取缓存
    noticFn.baseExerInfo.forEach((item) => {
      if (item.id == exer.questionTypeId) {
        curQuestionIndex.value = item.currentIndex;
        let questionIds = new Set(
          item.questions.map((item) => item.questionId)
        );
        questionIds.forEach((questionId) => {
          if (!exer.questionIds.includes(questionId)) {
            // 如果题目ID不在题目列表中,就把item.questions的该题删除
            item.questions = item.questions.filter(
              (q) => q.questionId !== questionId
            );
          }
        });
      }
    });
    if (curQuestionIndex.value == -1) {
      curQuestionIndex.value++;
    }
    if (curQuestionIndex.value + 1 > exer.questionIds.length) {
      curQuestionIndex.value = 0;
    }
  }
});

// 监听属性
watch(
  () => exer.orderShow[0],
  async (n, o) => {
    // 随机和顺序，同一个索引不是同一个题
    questionUpdate(curQuestionIndex.value);
    //rmkUpdate(questionId)
  }
);
watch(curQuestionIndex, async () => {
  questionUpdate(curQuestionIndex.value);
  //将题目缓存到noticFn.baseExerInfo
  noticFn.baseExerInfo.forEach((item) => {
    if (item.id == exer.questionTypeId) {
      item.currentIndex = curQuestionIndex.value;
    }
  });
  //rmkUpdate(questionId)
});

//字体设置
const size = ref("middle");
watchEffect(() => {
  size.value = noticFn.fontSize;
});

// 计算属性
const questionIdsOfShuffle = computed(() => {
  // 乱序后的试题列表，点随机的时候用
  return []
    .concat(exer.questionIds)
    .sort(() => (Math.random() > 0.5 ? -1 : 1)) as number[];
});
const questionNum = computed(() => {
  // 试题数量
  return exer.questionIds.length;
});
const diffMinute = computed(() => {
  // 答题时长（分钟数）
  return Math.ceil(
    (exer.lastTime.getTime() - exer.firstTime.getTime()) / 1000 / 60
  );
});
const questionLen = computed(() => {
  // 试题长度
  return exer.questionIds.length;
});

// 获取试题
async function getQuestion(questionId: number) {
  if (questionId == undefined) {
    return null;
  }
  if (!questionCache[questionId]) {
    let { data } = await http.post("myExer/question", {
      questionId,
    });
    data.userAnswers = []; // 接口没有，填充
    data.userScore = null; // 接口没有，填充
    questionCache[questionId] = data;
  }
  // 查询noticFn.myExerInfo中是否有该题的答案
  // 先查询是否为同一套题
  noticFn.baseExerInfo.forEach((item) => {
    if (item.id == exer.questionTypeId) {
      // 判断是否为同一题
      item.questions.forEach((q) => {
        if (q.questionId == questionId) {
          questionCache[questionId].userAnswers = q.answers;
        }
      });
    }
  });
  return questionCache[questionId] as Question;
}
const favClick = async (option) => {
  let questionIds = getQuestionIds();
  let currentQuestionId = questionIds[curQuestionIndex.value];

  //如果为真，添加收藏
  if (option) {
    let { code } = await http.post("myCollect/addAndUpdate", {
      questionId: currentQuestionId,
    });
    if (code == 200) {
      isFav.value = 1;
      //设置当前题目的收藏状态
      questionCache[currentQuestionId].collectFlag = 1;
    }
  } else {
    let { code } = await http.post("myCollect/delByQuestionId", {
      questionId: currentQuestionId,
    });
    if (code == 200) {
      isFav.value = 0;
      questionCache[currentQuestionId].collectFlag = 0;
    }
  }
};
// 创建 isFav 变量保存该题目是否被收藏
const isFav = ref(false);
//当前题目id
const curQuestionId = ref(null);

watchEffect(async () => {
  let questionIds = getQuestionIds();
  curQuestionId.value = questionIds[curQuestionIndex.value];
  let currentQuestion = await getQuestion(curQuestionId.value);
  isFav.value = currentQuestion?.collectFlag;
});

function changeAnswer(value) {
  exer.answerShow = value;
}
// 获取试题ID列表
function getQuestionIds() {
  return exer.orderShow[0] ? exer.questionIds : questionIdsOfShuffle.value;
}

/**
 * 试题更新
 * 一次更新三道题，当前题，上一题，下一题，使滑动换题更流畅
 *
 * @@param curQuestionIndex 当前试题索引
 */
async function questionUpdate(curQuestionIndex: number) {
  let questionIds = getQuestionIds(); // 获取试题ID列表

  let curIndex = curQuestionIndex;
  let curQuestion = await getQuestion(questionIds[curIndex]);

  let nextIndex =
    curQuestionIndex >= questionLen.value - 1 ? 0 : curQuestionIndex + 1;
  let nextQuestion = await getQuestion(questionIds[nextIndex]);

  let preIndex =
    curQuestionIndex <= 0 ? questionLen.value - 1 : curQuestionIndex - 1;
  let preQuestion = await getQuestion(questionIds[preIndex]);
  if (swiperIndex.value === 0) {
    questions.value[0] = curQuestion;
    questions.value[1] = nextQuestion;
    questions.value[2] = preQuestion;
  } else if (swiperIndex.value === 1) {
    questions.value[0] = preQuestion;
    questions.value[1] = curQuestion;
    questions.value[2] = nextQuestion;
  } else if (swiperIndex.value === 2) {
    questions.value[0] = nextQuestion;
    questions.value[1] = preQuestion;
    questions.value[2] = curQuestion;
  }
}
async function updateRxerInfo(question) {
  let found = false;

  noticFn.baseExerInfo.forEach((item) => {
    if (item.id === exer.questionTypeId) {
      let questionFound = false;
      item.questions.forEach((q) => {
        if (q.questionId === question.id) {
          q.answers = question.userAnswers;
          questionFound = true;
        }
      });

      if (!questionFound) {
        item.questions.push({
          questionId: question.id,
          answers: question.userAnswers,
        });
      }
      found = true;
    }
  });

  if (!found) {
    noticFn.baseExerInfo.push({
      id: exer.questionTypeId,
      currentIndex: curQuestionIndex.value,
      questions: [
        {
          questionId: question.id,
          answers: question.userAnswers,
        },
      ],
    });
  }
  let { data } = await http.post("exmMyExer/save", {
    type: 2,
    content: JSON.stringify(noticFn.baseExerInfo),
  });
}
// 试题批阅
function questionMark(question: Question) {
  if (!exer.answerShow) {
    return;
  }

  // 判断noticFn.myExerInfo数组是否存在本次练习
  updateRxerInfo(question);
  if (question.type === 1 || question.type === 4) {
    // 如果是单选或判断
    if (question.userScore == null) {
      // 并且没打分
      if (question.userAnswers && question.userAnswers[0]) {
        // 并且有答案
        question.userScore = 0;
        if (question.userAnswers[0] === question.answers[0]) {
          // 打分
          question.userScore = question.score;
        }
      }
    }
  }
  if (question.type === 2) {
    // 如果是多选
    if (question.userScore == null) {
      // 并且没打分
      if (question.userAnswers && question.userAnswers[0]) {
        // 并且有答案
        question.userScore = 0;
        let include = question.userAnswers.every((userAnswer: string) =>
          question.answers.includes(userAnswer)
        );

        if (
          include &&
          question.answers.length === question.userAnswers.length
        ) {
          // 全对满分
          question.userScore = question.score;
        } else if (include) {
          // 半对指定分
          question.userScore = question.scores[0] ? question.scores[0] : 0.5;
          questions.value[swiperIndex.value].userScore = question.userScore;
        } else {
          question.userScore = 0;
          questions.value[swiperIndex.value].userScore = question.userScore;
        }
      }
    }
  }
}

// 模拟结束
function exerEnd() {
  let questionIds = getQuestionIds();

  let total = questionIds.length;
  let trueNum = 0;
  let falseNum = 0;
  questionIds.forEach((questionId) => {
    if (
      questionCache[questionId] &&
      questionCache[questionId].userScore != null
    ) {
      if (
        questionCache[questionId].userScore === questionCache[questionId].score
      ) {
        trueNum++;
      } else {
        falseNum++;
      }
    }
  });

  uni.showModal({
    title: "提示消息",
    content: "练习已完成",
    showCancel: false,
    success: function (res) {
      uni.navigateTo({
        url: `/pages/myBase/myBaseResult?total=${total}&trueNum=${trueNum}&falseNum=${falseNum}&diffMinute=${diffMinute.value}`,
      });
    },
  });
}

// 上一题
async function pre() {
  let questionIds = getQuestionIds();
  if (exer.answerShow) {
    // 如果是答题模式
    let curQuestion = await getQuestion(questionIds[curQuestionIndex.value]);
    if (
      curQuestion.type === 1 ||
      curQuestion.type === 2 ||
      curQuestion.type === 4
    ) {
      // 如果是单选多选判断
      if (curQuestion.userAnswers.length) {
        // 并且已答题
        if (curQuestion.userScore == null) {
          // 并且没打分
          questionMark(curQuestion); // 打分

          if (curQuestion.score != curQuestion.userScore) {
            // 如果不是满分，不进入下一题（第二次就打分了，不在进入）
            return;
          }
        }
      }
    }
  }

  curQuestionIndex.value <= 0
    ? (curQuestionIndex.value = questionLen.value - 1)
    : curQuestionIndex.value--; // 划到上一题
}

// 下一题
async function next() {
  let questionIds = getQuestionIds();
  let curQuestion = await getQuestion(questionIds[curQuestionIndex.value]);

  if (
    curQuestion.type === 1 ||
    curQuestion.type === 2 ||
    curQuestion.type === 4
  ) {
    console.log(curQuestion, "在next中");

    if (curQuestion.userAnswers.length) {
      // 并且已答题
      if (curQuestion.userScore === null) {
        // 并且没打分
        questionMark(curQuestion); // 打分
        // questionUpdate(0);

        //判断当前题目是不是exer.questionIds第一个id

        if (curQuestion.score != curQuestion.userScore) {
          // 如果不是满分，不进入下一题（第二次就打分了，不在进入）
          return;
        }
      }
    }
  }

  curQuestionIndex.value >= questionLen.value - 1
    ? (curQuestionIndex.value = 0)
    : curQuestionIndex.value++;
}
function updataCache(question: Question) {
  questionCache[question.id] = question;
}
// 自动下一题
function autoNext(question: Question) {
  // 更新一下用户答案
  updataCache(question);
  exer.lastTime = new Date(); // 答题就更新时间
  if (question.type === 1 || question.type === 4) {
    // 如果是单选或判断
    if (exer.answerShow) {
      // 并且是答题模式
      questionMark(question);
      if (question.score === question.userScore) {
        // 并且答对
        setTimeout(() => {
          next(); // 自动下一题
        }, 500);
      }
    }
  } else {
    updateRxerInfo(question);
  }
}

/**
 * 同步索引
 * 类似小齿轮带动大齿轮转动
 *
 * @param newSwiperIndex 滑动试图索引
 * @@param source
 */
function synIndex(newSwiperIndex: number, source: string) {
  if (source !== "touch") {
    // 不是滑动触发，不处理
    return;
  }

  let oldSwiperIndex = swiperIndex.value;
  if (
    oldSwiperIndex - newSwiperIndex === -2 ||
    oldSwiperIndex - newSwiperIndex === 1
  ) {
    // 右滑
    swiperIndex.value <= 0 ? (swiperIndex.value = 2) : swiperIndex.value--;
    curQuestionIndex.value <= 0
      ? (curQuestionIndex.value = questionLen.value - 1)
      : curQuestionIndex.value--;
  } else {
    // 左滑
    swiperIndex.value >= 2 ? (swiperIndex.value = 0) : swiperIndex.value++;
    curQuestionIndex.value >= questionLen.value - 1
      ? (curQuestionIndex.value = 0)
      : curQuestionIndex.value++;
  }
}

// 是否答题
function hasDo(questionId: number) {
  let flag = false;
  noticFn.baseExerInfo.forEach((item) => {
    if (item.id === exer.questionTypeId) {
      item.questions.forEach((q) => {
        if (q.questionId === questionId) {
          flag = true;
        }
      });
    }
  });

  return flag;
}
// 是否标记
function hasMark(questionId: number) {
  return markQuestions.value.includes(questionId);
}

// 是否答对
function hasTrue(questionId: number) {
  let question = questionCache[questionId] as Question;
  if (question && question.userScore != null) {
    return question.userScore === question.score;
  }
  return false;
}

// 是否答错
function hasFalse(questionId: number) {
  let question = questionCache[questionId] as Question;
  if (question && question.userScore != null) {
    return question.userScore === 0;
  }
  return false;
}

// 是否半对
function hasHalf(questionId: number) {
  let question = questionCache[questionId] as Question;
  if (question && question.userScore != null) {
    return question.userScore > 0 && question.userScore !== question.score;
  }
  return false;
}
</script>

<style lang="scss" scoped>
:deep(.my-exer-page) {
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  .my-exer-page-feedback {
    position: absolute;
    right: 20rpx;
    top: 650rpx;
    z-index: 10;
  }
  .my-exer-page-chapter-name {
    font-size: 28rpx;
    font-weight: bold;
    margin-bottom: 20rpx;
  }
  .my-exer-page-chapter-txt {
    font-size: 34rpx;
    color: $uni-base-color;
  }
  .my-exer-page-head {
    display: flex;
    justify-content: space-around;
    padding: 20rpx;
    border-bottom: 2rpx solid $uni-border-1;
    .button {
      position: relative;
      padding-bottom: 10rpx;
    }
    .active::after {
      content: "";
      position: absolute;
      bottom: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 50rpx; /* 设置底部边框的宽度 */
      height: 1px; /* 设置底部边框的高度 */
      background-color: #01bafd; /* 设置底部边框的颜色 */
    }
    .small {
      font-size: 28rpx;
    }
    .middle {
      font-size: 32rpx;
    }
    .large {
      font-size: 36rpx;
    }
    .checklist-box {
      margin-right: 20rpx;
    }
    .favBtn {
      margin-top: 6rpx;
    }
  }
  .uni-card__content {
    flex: 1;
    uni-swiper {
      height: 100%;
    }
  }
  .uni-card__actions {
    height: 100rpx;
    border-top: 2rpx #eee solid;
    display: flex;
    font-size: 26rpx;
    .small {
      font-size: 28rpx;
      flex: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      border-right: 1px solid #eee;
      &:active {
        background-color: #eee;
      }
    }
    .middle {
      font-size: 32rpx;
      flex: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      border-right: 1px solid #eee;
      &:active {
        background-color: #eee;
      }
    }
    .large {
      font-size: 36rpx;
      flex: 1;
      display: flex;
      justify-content: center;
      align-items: center;
      border-right: 1px solid #eee;
      &:active {
        background-color: #eee;
      }
    }
  }
  .uni-grid-item--border {
    border-radius: 50%;
    justify-content: center;
    align-items: center;
    margin: 2px;
  }

  .my-exer-page-card {
    .uni-card__actions {
      display: none;
    }
    .uni-grid {
      border-left-width: 0px;
      .uni-grid-item--border {
        border: 1px #d2d2d2 solid;
      }
    }

    .my-exer-page-card-tips {
      margin-bottom: 10rpx;
      uni-text {
        display: flex;
        align-items: center;
        margin-right: 12rpx;
      }
      .my-exer-page-card-do {
        .uni-grid-item--border {
          background-color: $uni-primary-disable;
          color: white;
        }
      }

      .my-exer-page-card-true {
        position: relative;
        &:before {
          font-family: "iconfont";
          content: "\ec9e";
          position: absolute;
          right: -0rpx;
          bottom: -4rpx;
          font-weight: bold;
          font-size: 30rpx;
          color: $uni-success;
          z-index: 1;
        }
      }
      .my-exer-page-card-false {
        position: relative;
        &:before {
          font-family: "iconfont";
          content: "\e6e5";
          position: absolute;
          right: -0rpx;
          bottom: -4rpx;
          font-weight: bold;
          font-size: 30rpx;
          color: $uni-error;
          z-index: 1;
        }
      }
      .my-exer-page-card-half {
        position: relative;
        &:before {
          font-family: "iconfont";
          content: "\e642";
          position: absolute;
          right: 0rpx;
          bottom: -4rpx;
          font-weight: bold;
          font-size: 30rpx;
          color: $uni-error;
          z-index: 1;
        }
      }
      .my-exer-page-card-mark {
        position: relative;
        &:before {
          font-family: "iconfont";
          content: "\e660";
          position: absolute;
          right: -0rpx;
          top: -0rpx;
          font-weight: bold;
          font-size: 30rpx;
          color: $uni-error;
          z-index: 1;
        }
      }
    }
  }
}
</style>
